home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Languages / Mops 2.7 / Mops source / Toolbox classes / PrintManager < prev    next >
Encoding:
Text File  |  1994-05-08  |  7.1 KB  |  264 lines  |  [TEXT/MSET]

  1.     \ 24Jul92 DBH
  2.  
  3. \ note that dlen from the source file class was redefined as a value in
  4. \ the source file struct
  5. : DataLength    ( ^class -- n )  \ given a pointer to a class, return the
  6.                                  \ length of the ivar data
  7.     dlen&xwid drop ;
  8.  
  9.  
  10. \ define the non-trivial toolbox calls as normal words, not required, but
  11. \ this makes it easier to follow the methods, I think
  12.  
  13. : PrValidate  { thPrint -- b }
  14.     word0 thPrint call PrValidate i->l ;
  15.     
  16. : PrStlDialog  { thPrint -- b }
  17.     word0 thPrint call PrStlDialog i->l ;
  18.     
  19. : PrJobDialog  { thPrint -- b }
  20.     word0 thPrint call PrJobDialog i->l ;
  21.     
  22. : PrOpenDoc { thPrint tpPrPort tpIOBuf -- TPPrPort }
  23.     0 thPrint tpPrPort tpIOBuf call PrOpenDoc ;
  24.     
  25. : PrError ( -- errorCode )
  26.     word0 call PrError i->l ;
  27.  
  28. \ now define some classes for the purpose of mapping into the Mac records
  29.  
  30. :class TPrInfo    super{ object }
  31. record
  32. {    int        iDev
  33.     int        iVRes    \ vertical resolution of printer
  34.     int        iHRes    \ horizontal resolution of printer
  35.     rect    rPage    \ page rectangle
  36. }
  37. ;class
  38.  
  39.  
  40. :class TPrStl    super{ object }
  41. record
  42. {    int        wDev    \ high byte specifies device (1=ImageWriter, 3=LaserWriter)
  43.     6 bytes junk    \ more fields for internal use, not mapped
  44. }
  45. ;class
  46.  
  47.  
  48. :class TPrJob  super{ object }
  49. record
  50. {    int        iFstPage
  51.     int        iLstPage
  52.     int        iCopies
  53.     byte    bJDocLoop    \ print method, 0=draft  1=spooled
  54.     bool    fFromUsr
  55.     ptr        pIdleProc    \ background procedure
  56.     ptr        pFileName
  57.     4 bytes junk
  58. }
  59.  
  60. :m spooled?:    ( -- b)
  61.     get: bJDocLoop  1 = ;m
  62.  
  63. ;class
  64.  
  65.  
  66. :class THPrint    super{ object }
  67. record
  68. {    int            iPrVersion
  69.     TPrInfo        prInfo
  70.     rect        rPaper
  71.     TPrStl        prStl
  72.     TPrInfo        prInfoPT
  73.     16 bytes    prXInfo        \ not mapped due to very limited use
  74.     TPrJob        prJob
  75.     38 bytes    printX
  76. }
  77.  
  78. :m spooled?:    ( -- b)
  79.     spooled?: prJob ;m
  80.  
  81. ;class
  82.  
  83.  
  84. :class  TPrStatus  super{ object }
  85. record
  86. {    int        iTotPages        \ number of pages in spool file
  87.     int        iCurPage        \ page being printed
  88.     int        iTotCopies        \ number of copies requested
  89.     int        iCurCopy        \ copy being printed
  90.     int        iTotBands        \ used internally
  91.     int        iCurBand        \ used internally
  92.     bool    fPgDirty        \ true if started printing page
  93.     bool    fImaging        \ used internally
  94.     handle    hPrint            \ print record
  95.     var        pPrPort            \ printing grafport
  96.     handle    hPic            \ used internally
  97. }
  98. ;class
  99.  
  100.  
  101. :class PrintManager super{ object }
  102.     
  103.     handle         hPrint
  104.     TPrStatus    prStatus
  105.     x-addr        draw    \ draw handler for printing
  106.     
  107.  
  108. :m put:    ( cfa -- )
  109.     put: draw ;m
  110.  
  111. :m new:        \ must call new: only once at runtime to allocate print record
  112.     ['] THPrint DataLength  new: hPrint ;m
  113.  
  114. :m getnew:    \ this method should obtain a print record from the resource
  115.     \ fork of the file, if a file exists that is ( see PageSetup: comments
  116.     \ and see IM II-150 Note: )
  117.     \ This method is not implemented here, but would be used in place of new:.
  118.     ;m
  119.  
  120. :m release:
  121.     release: hPrint ;m
  122.  
  123. :m PageSetup:    ( -- b)    \ rundialog, returns 0 if user cancel
  124.     \ if user did not cancel, it might be a good idea to save the hprint record
  125.     \ to disk so the printing parameters chosen by the user can be restored.
  126.     \ But this restoration is not automatic and must be done by the program.
  127.     call PrOpen
  128.     PrError 0=
  129.     IF
  130.         get: hPrint PrStlDialog
  131.     THEN
  132.     call PrClose ;m
  133.  
  134. private
  135.  
  136. \ note, only printing one page here ( so this isn't really a loop)
  137. :m printLoop:    { \ pPrPort -- }
  138.     get: hPrint 0 0 PrOpenDoc -> pPrPort
  139.     PrError 0=
  140.     IF
  141.         pPrPort 0 call PrOpenPage    \ pPageFrame=0, so no scaling
  142.         PrError 0=
  143.         IF
  144.             exec: draw
  145.         THEN
  146.         pPrPort call PrClosePage
  147.     THEN
  148.     pPrPort call PrCloseDoc
  149.     
  150.     PrError 0=
  151.     ptr: hPrint  spooled?: THPrint  and        \ note message to class THPrint
  152.         IF
  153.             get: hPrint 0 0 0 addr: prStatus call PrPicFile
  154.         THEN
  155. ;m
  156.     
  157. public
  158.  
  159. :m Print:
  160.     call PrOpen
  161.     PrError 0=
  162.     IF
  163.         pushport
  164.         
  165.         get: hPrint PrJobDialog
  166.         IF printLoop: self THEN
  167.         
  168.         popport
  169.     THEN
  170.     call PrClose ;m
  171.  
  172. ;class
  173.  
  174. PrintManager  pm    \ instantiate an object, named pm, to do all printing work
  175.  
  176. endload
  177.  
  178.  
  179.  
  180.  
  181. ********* Example usage of Print Manager **********
  182.  
  183. : testPrint
  184.     30 30 80 80 put: temprect
  185.     draw: temprect ;
  186.  
  187. ' testPrint put: pm        \ put the draw action in our PrintManager object
  188.  
  189.  
  190. new: pm                    \ must always call new: only once at runtime
  191.  
  192. PageSetup: pm .            \ not required, but does what it says
  193. Print: pm                \ let er rip
  194.  
  195. release: pm            \ not required till quitting, i.e. can do multiple Print:'s
  196.                     \ without calling this.  This just releases some memory.
  197.  
  198.  
  199.  
  200. ****** Possible Enhancements ********
  201.  
  202. Of course, we need to cycle through and print each requested page.
  203.  
  204. I think a better printing model could be achieved by having a " print object"
  205. instance variable in the PrintManager class.  It would simply be sent a 
  206. print: message at the correct time, rather than sending exec: to an x-addr
  207. as is done here.  I think it would be more flexible and robust to have the
  208. PrintManager object communicate with a print object.
  209.  
  210. It would probably make sense to have printing be a function of the
  211. page rectangle and page number.  So the print object would always
  212. be passed this information when a page is requested to be drawn.
  213. And probably the message should be PrintPage: with the rectangle and
  214. page number passed as parameters to the print object.
  215.  
  216. Also, a way to easily save and restore the the page setup parameters in a
  217. file's resource fork would be nice.  See suggested message getnew:.
  218.  
  219. SInce no background procedure is provided, the toolbox will default to
  220. cancelling upon command-period.  See IM II-152,153.  But it shouldn't be
  221. difficult to provide a custom background procedure.
  222.  
  223.  
  224. ****** Comments *******
  225.  
  226. Note the use of a class definition to map into a toolbox-created record,
  227. in this case the THPrint record.  In the printLoop: method of class PrintManager
  228. we need to access a member of a record that is contained in a subrecord, in
  229. this case bjDocLoop (member of TPrJob, which is a subrecord of THPrint).
  230. Now we could have simply obtained the pointer to the print record, added
  231. the correct offset, and performed a c@:
  232.  
  233.     ptr: hPrint  offset + c@
  234.     
  235. But there are some problems with this approach, even though it may seem more
  236. straightforward.  First, one must compute the offset.  I have no idea what it
  237. is, nor do I wish to know.  Second, one must remember to perform the correct
  238. type of "fetch" (c@ here, or was it c@x?).  Thirdly, I don't think it is very
  239. clear what is going on here.
  240.  
  241. Instead, I believe a better approach is to define the records as classes,
  242. define the required access methods, and then pass a message to a class with
  243. the appropriate base address on the stack:
  244.  
  245.     ptr: hPrint   spooled?: THPrint
  246.  
  247. Here the spooled?: message will be passed by class THPrint to its prJob ivar
  248. which will obtain the value of bjDocLoop contained in the record pointed to
  249. by  ptr: hPrint.
  250.  
  251. One must be careful when passing a message to a class that the address
  252. on the stack really does point to a data structure that matches the class.
  253. The offset (to bjDocLoop) is automatically computed, the appropriate "fetch"
  254. is automatically performed, and it is very clear what is going on.  Also,
  255. one does not need to know the length of the THPrint record when allocating
  256. memory for the handle hPrint.  Merely passing the class pointer to DataLength
  257. will do that job  ( see definition of DataLength at the beginning of this file)
  258. as in the new: method for PrintManager.
  259.  
  260.  
  261.  
  262. Doug Hoffman      24Jul92
  263.  
  264. Compuserve 72310,1743